package com.sunreal.paygateway.Interceptors;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.alibaba.fastjson.JSONObject;
import com.sunreal.paygateway.Interceptors.Wrapper.RequestWrapper;
import com.sunreal.paygateway.common.PayConstant;
import com.sunreal.paygateway.sys.annotations.RequestSign;
import com.sunreal.paygateway.dao.mapper.MchInfoMapper;
import com.sunreal.paygateway.dao.model.MchInfo;
import com.sunreal.paygateway.sys.exception.WebErrCode;
import com.sunreal.paygateway.sys.util.GsonUtil;
import com.sunreal.paygateway.sys.util.PayDigestUtil;
import com.sunreal.paygateway.sys.util.result.WebResult;

/**
 * 功能描述：//TODO
 *
 * @Author 彭广
 * @Date 2019/1/18
 */
@Component
@Slf4j
public class ParameterSignInterceptor extends HandlerInterceptorAdapter {

    public static final String VERIFY_FAIL_MSG = "The request parameter signature verification failed!";

    @Autowired
    private MchInfoMapper mchInfoMapper;

    /**
     * 该方法将在请求处理之前进行调用，只有该方法返回true，才会继续执行后续的Interceptor和Controller，
     * 如果已经是最后一个Interceptor的时候就会是调用当前请求的Controller方法；
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod method = (HandlerMethod) handler;
            RequestSign requestSign = method.getMethodAnnotation(RequestSign.class);
            if (requestSign == null || !(requestSign.value())) {
                return true;
            }
        }
        RequestWrapper requestWrapper = new RequestWrapper(request);
        String params = requestWrapper.getBody();
        if (StringUtils.isBlank(params)) {
            return true;
        }
        JSONObject jsonObject = JSONObject.parseObject(params);
        // 商户号
        String mchid = jsonObject.getString(PayConstant.PARAM_MCHID);
        // 签名
        String signStr = jsonObject.getString(PayConstant.PARAM_SIGN);
        if (StringUtils.isBlank(mchid) || StringUtils.isBlank(signStr)) {
            SendVerifyFail(response, HttpStatus.SC_BAD_REQUEST);
            return false;
        }
        MchInfo mchInfo = mchInfoMapper.selectByPrimaryKey(mchid);
        if (mchInfo == null) {
            SendVerifyFail(response, HttpStatus.SC_BAD_REQUEST);
            return false;
        }
        String sign = PayDigestUtil.getSign(jsonObject.getInnerMap(), mchInfo.getReqkey(), PayConstant.PARAM_SIGN);
        log.debug(sign);
        if (sign.equalsIgnoreCase(signStr)) {
            log.debug("验签成功！");
            return true;
        }
        SendVerifyFail(response, HttpStatus.SC_FORBIDDEN);
        return false;
    }

    private void SendVerifyFail(HttpServletResponse response, int httpStatus) {
        log.warn(VERIFY_FAIL_MSG);
        response.setStatus(httpStatus);
        response.setContentType(PayConstant.CONTENT_TYPE);
        try (PrintWriter writer = response.getWriter()) {
            writer.print(GsonUtil.toJson(WebResult.retFail(WebErrCode.SIGN_VERIFY_FAILED)));
        } catch (IOException e) {
            log.error("response error", e);
        }
    }

    /**
     * 该方法也是需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行，
     * 该方法将在整个请求结束之后，也就是在DispatcherServlet 渲染了对应的视图之后执行。用于进行资源清理。
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }

    /**
     * 该方法将在请求处理之后，DispatcherServlet进行视图返回渲染之前进行调用，
     * 可以在这个方法中对Controller 处理之后的ModelAndView 对象进行操作。
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    }

}
